package com.longqin.wechat.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.longqin.wechat.entity.MyException;
import com.longqin.wechat.entity.Template;
import com.longqin.wechat.entity.WeChatCode;
import com.longqin.wechat.entity.WxAccessToken;
import com.longqin.wechat.entity.WxUserInfo;
import com.longqin.wechat.mapper.WxUserMapper;
import com.longqin.wechat.service.CommSerive;
import com.longqin.wechat.service.WxService;
import com.longqin.wechat.util.MyObjectUtil;
import com.longqin.wechat.util.RedisUtil;
import com.longqin.wechat.util.ResponseEnum;
import com.longqin.wechat.util.SpringUtil;

/**
 * @Description: 微信业务接口实现类
 * @Author longqin
 * @Date 2025-05-07
 * 
 */
@Service
public class WxServiceImpl extends CommSerive implements WxService{
	
	private static final Logger LOG = LoggerFactory.getLogger(WxServiceImpl.class);
	
	@Value("${appid}")
	private String appid;

	@Value("${secret}")
	private String secret;
	
	@Value("${oauth2Url}")
	private String oauth2Url;//获取微信公众号openId
	
	@Value("${access_token_url}")
	private String access_token_url;
	
	@Value("${userInfo_url}")
	private String userInfo_url;//获取微信用户信息url

	@Value("${template_url}")
	private String template_url;
	
	@Resource
	private RedisUtil redisUtil;
	
	private static final String PUBLIC_KEY = "longqinwx";
	
	@Resource
	private WxUserMapper wxUserMapper;

	@Override
	public WxAccessToken getOpenId(String code) throws Exception {
		Map<String, String> vars = new HashMap<String,String>();
		vars.put("appid", appid);
		vars.put("secret", secret);
		vars.put("code", code);
		String data = getRest(oauth2Url, vars);
		WxAccessToken body = new Gson().fromJson(data, WxAccessToken.class);
    	String openId = body.getOpenid();
    	if(!MyObjectUtil.isNotNull(openId)){
    		throw new MyException(ResponseEnum.ERROR.getCode(),"获取openId失败:" + body.getErrmsg());
    	}
    	return body;
	}
	
	@Override
	@Cacheable(value="access",key="'token'")
	public String getAccessToken() throws Exception {
		Map<String, String> vars = new HashMap<String,String>();
		vars.put("appid", appid);
		vars.put("secret", secret);
		String data = getRest(access_token_url, vars);
		WxAccessToken body = new Gson().fromJson(data, WxAccessToken.class);
    	String access_token = body.getAccess_token();
    	if(!MyObjectUtil.isNotNull(access_token)){
    		throw new MyException(ResponseEnum.ERROR.getCode(),"获取accessToken失败:" + body.getErrmsg());
    	}
    	LOG.info("获取access_token({})", access_token);
    	return access_token;
	}

	/**
	 * 待优化-如果缓存不存在，用户可能首次登录或者缓存过期，这时候插入/更新数据库，因为用户头像和昵称可能换更换
	 * **/
	@Override
	public WxUserInfo getUserInfo(String access_token, String openid) throws Exception {
		if(redisUtil.hasKey(PUBLIC_KEY)){
			WxUserInfo body = (WxUserInfo) redisUtil.hGet(PUBLIC_KEY, openid);
			if(null == body || !MyObjectUtil.isNotNull(body.getOpenId())
					|| !MyObjectUtil.isNotNull(body.getNickName())){
				body = new WxUserInfo();
				body.setOpenId(openid);
				redisUtil.hSet(PUBLIC_KEY, openid, body);
			}
			return body;
		}else{
			WxUserInfo body = new WxUserInfo();
			body.setOpenId(openid);
			redisUtil.hSet(PUBLIC_KEY, openid, body, 30, TimeUnit.DAYS);
			return body;
		}
	}
	
	/**发送模板消息
	 * @param template 模板内容
	 * @return
	 * @throws Exception 
	 */
	@Override
	public boolean sendTemplate(Template template) throws Exception {
		WxServiceImpl service = (WxServiceImpl) SpringUtil.getBean(WxServiceImpl.class);
		String access_token = service.getAccessToken();
		Map<String, String> vars = new HashMap<String,String>();
		vars.put("access_token", access_token);
		String body = postRest(template_url, template, vars, "发送模板消息失败");
		WeChatCode result = JSON.parseObject(body,WeChatCode.class);
		if(result.getErrcode()==0)return true;
		else throw new MyException(ResponseEnum.ERROR.getCode(),"发送模板消息失败:"+result.getErrmsg());
	}

}
